package com.fashiontextile.auth.service.impl;

import com.fashiontextile.auth.service.TokenService;
import com.fashiontextile.common.constant.TokenConstants;
import com.fashiontextile.common.entity.LoginUser;
import com.fashiontextile.common.utils.JwtUtils;
import com.fashiontextile.common.utils.RedisUtils;
import com.fashiontextile.user.entity.User;
import com.nimbusds.jose.JOSEException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author brooke_zb
 */
@Slf4j
@Service
@AllArgsConstructor
public class TokenServiceImpl implements TokenService {
    private RedisUtils redisUtils;

    @Override
    public Map<String, Object> createToken(User user) throws JOSEException {
        String token = UUID.randomUUID().toString();

        LoginUser loginUser = new LoginUser();
        loginUser.setUid(user.getUid());
        loginUser.setUsername(user.getUsername());
        loginUser.setRole(user.getRole().getName());

        // 储存信息至redis
        storeToken(token, user.getUid());
        storeLoginUser(loginUser);

        // JWT载荷
        Map<String, Object> claims = new HashMap<>();
        claims.put("token", token);
        claims.put("uid", user.getUid());

        // 返回信息
        Map<String, Object> result = new HashMap<>();
        result.put("accessToken", JwtUtils.createToken(claims));
        result.put("expireIn", TokenConstants.EXPIRATION);
        return result;
    }

    @Override
    public void deleteToken(String jwt) throws JOSEException, ParseException {
        LoginUser user = getLoginUser(jwt);
        redisUtils.delete(TokenConstants.REDIS_PREFIX + user.getUid() + ":" + user.getToken());
    }

    @Override
    public LoginUser getLoginUser(String jwt) throws JOSEException, ParseException {
        Map<String, Object> payload = JwtUtils.parseToken(jwt);
        String token = (String) payload.get("token");
        Long uid = (Long) payload.get("uid");

        return getLoginUser(token, uid);
    }

    private void storeToken(String token, Long uid) {
        redisUtils.setStringValue(TokenConstants.REDIS_PREFIX + uid + ":" + token,
                String.valueOf(System.currentTimeMillis()),
                TokenConstants.EXPIRATION,
                TimeUnit.MINUTES);
    }

    private void storeLoginUser(LoginUser user) {
        redisUtils.setObjectValue(TokenConstants.REDIS_PREFIX + user.getUid(), user);
    }

    private LoginUser getLoginUser(String token, Long uid) {
        LoginUser user = (LoginUser) redisUtils.getObjectValue(TokenConstants.REDIS_PREFIX + uid);
        user.setToken(token);
        return user;
    }
}
